use std::fmt;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;

use parking_lot::Mutex;

use super::mpmc_attr::*;
use super::mpmc_scheduler::MpmcTaskScheduler;
use schedule::exec::*;

#[derive(Debug, Clone)]
enum TestTask1 {
    Generate,
    Roll(Vec<u8>),
    Select(u128, u128),
    Max(u128),
}

impl TestTask1 {

}

#[derive(Debug, Clone)]
enum TestTaskError { }

impl fmt::Display for TestTaskError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "test task error")
    }
}

impl std::error::Error for TestTaskError { }

const GENERATE_LEN:usize = 1000;

impl TestTask1 {
    fn exec<S:schedule::exec::TaskScheduler<Self>>(&self, ctx:Option<&mut u128>, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), TestTaskError> {
        match self {
            TestTask1::Generate => {
                let mut seed = 1u128;
                for _ in 0..GENERATE_LEN {
                    let mut data = vec![0u8;4096];
                    for i in 0..4096 {
                        data[i] = (((seed * 1341410813) % 5422352) & 255) as u8;
                        seed += 1;
                    }
                    S::send_with_count(sender, TestTask1::Roll(data), &task_counter);
                }
            }
            TestTask1::Roll(data) => {
                let mut max_feature1 = 0;
                let mut max_feature2 = 0;
                for &byte in data {
                    let feature1 = ((byte as u128 * 21238214712) % 839341) & 65536;
                    let feature2 = ((byte as u128 * 78131941041) % 913417) & 65536;
                    max_feature1 = std::cmp::max(max_feature1, feature1);
                    max_feature2 = std::cmp::max(max_feature2, feature2);
                }
                S::send_with_count(sender, TestTask1::Select(max_feature1, max_feature2), &task_counter);
            }
            TestTask1::Select(feature1, feature2) => {
                let feature = (feature1 + feature2) / 2;
                S::send_with_count(sender, TestTask1::Max(feature), &task_counter);
            }
            TestTask1::Max(feature) => {
                let ctx = ctx.unwrap();
                *ctx = std::cmp::max(*feature, *ctx);
            }
        };
        Ok(())
    }
}


#[derive(Debug, Clone)]
pub struct TestTaskSenderGroup1 {
    gen_sender:std::sync::mpmc::Sender<ProcessControlTask<TestTask1>>,
    roll_sender:std::sync::mpmc::Sender<ProcessControlTask<TestTask1>>,
    select_sender:std::sync::mpmc::Sender<ProcessControlTask<TestTask1>>,
    max_sender:std::sync::mpmc::Sender<ProcessControlTask<TestTask1>>,
    terminal_sender:std::sync::mpmc::Sender<()>,
}

#[cfg(test)]
impl MpmcTaskAttr for TestTask1 {
    type SenderGroup = TestTaskSenderGroup1;
    fn predefine_sender(sched:&mut MpmcTaskScheduler<Self>) {
        let name_list = ["generate", "roll", "select", "max",];
        name_list.iter().for_each(|&name|sched.register_specific_executor_name(name));
    }

    fn group_send(sender_group:&Self::SenderGroup, process_control_task:ProcessControlTask<Self>) {
        let task = if let ProcessControlTask::Task(task) = &process_control_task { task } else { panic!("group send break"); };
        match &task {
            Self::Generate => &sender_group.gen_sender,
            Self::Roll(_) => &sender_group.roll_sender,
            Self::Select(_, _) => &sender_group.select_sender,
            Self::Max(_) => &sender_group.max_sender,
        }.send(process_control_task).expect("group send error")
    }

    fn get_sender_group_from(sched:&MpmcTaskScheduler<Self>) -> Result<Self::SenderGroup, String> {
        let gen_sender = sched.get_specific_sched_sender("generate").ok_or("generate".to_string())?;
        let roll_sender = sched.get_specific_sched_sender("roll").ok_or("roll".to_string())?;
        let select_sender = sched.get_specific_sched_sender("select").ok_or("select".to_string())?;
        let max_sender = sched.get_specific_sched_sender("max").ok_or("max".to_string())?;
        let terminal_sender = sched.get_exec_terminal_sender();
        Ok(TestTaskSenderGroup1 {
            gen_sender, roll_sender, select_sender, max_sender, terminal_sender,
        })
    }

    fn send_init_task(sched:&MpmcTaskScheduler<Self>, init_task:Self) {
        sched.get_specific_sched_sender("generate").unwrap().send(ProcessControlTask::Task(init_task)).expect("init error");
    }

    fn get_exec_terminal_sender(sender_group:&Self::SenderGroup) -> std::sync::mpmc::Sender<()> {
        sender_group.terminal_sender.clone()
    }
}

pub struct GenerateExecutor;
impl TaskExecutor<TestTask1> for GenerateExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask1>>(&mut self, task:TestTask1, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(None, sender, task_counter)
    }
}

pub struct RollExecutor;
impl TaskExecutor<TestTask1> for RollExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask1>>(&mut self, task:TestTask1, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(None, sender, task_counter)
    }
}

pub struct SelectExecutor;
impl TaskExecutor<TestTask1> for SelectExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask1>>(&mut self, task:TestTask1, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(None, sender, task_counter)
    }
}

pub struct MaxExecutor { max:std::sync::Arc<Mutex<u128>>, tmp_max:u128 }
impl MaxExecutor {
    pub fn new(max:std::sync::Arc<Mutex<u128>>) -> Self { 
        let tmp_max = *max.lock();
        Self { max, tmp_max } 
    }
}

impl TaskExecutor<TestTask1> for MaxExecutor {
    type Error = TestTaskError;
    fn exec<S:TaskScheduler<TestTask1>>(&mut self, task:TestTask1, sender:&S::Sender, task_counter:Arc<AtomicUsize>) -> Result<(), Self::Error> {
        task.exec::<S>(Some(&mut self.tmp_max), sender, task_counter)
    }
}

impl Drop for MaxExecutor {
    fn drop(&mut self) {
        *self.max.lock() = self.tmp_max;
    }
}


pub(crate) fn test_mpmc_specific_exec() {
    let max_num = Arc::new(Mutex::new(0));
    let mut task_scheduler = MpmcTaskScheduler::<TestTask1>::new(TestTask1::Generate);
    let gen_exec = GenerateExecutor;
    let roll_exec = RollExecutor;
    let select_exec = SelectExecutor;
    let max_exec = MaxExecutor::new(max_num.clone());
    task_scheduler.register_specific_executor("generate".to_string(), gen_exec);
    task_scheduler.register_specific_executor("roll".to_string(), roll_exec);
    task_scheduler.register_specific_executor("select".to_string(), select_exec);
    task_scheduler.register_specific_executor("max".to_string(), max_exec);
    
    let now = std::time::Instant::now();
    task_scheduler.schedule().expect("schedule error");
    let task_time = now.elapsed().as_micros();
    println!("max feature:{}", max_num.lock());
    println!("test specific exec time:{}", task_time);
}